<template>
  <el-dialog v-model="dialogVisible" :title="parameter.title" width="680px" lock-scroll destroy-on-close draggable>
    <el-form ref="formRef" :model="parameter.template" :rules="rules" label-width="100px" label-suffix=" :">
      <el-form-item label="模版名称" prop="name">
        <el-input v-model="parameter.template.name" placeholder="请填写模版名称" clearable />
      </el-form-item>
      <el-form-item label="模版编码" prop="code">
        <el-input v-model="parameter.template.code" placeholder="请填写模版编码" clearable />
      </el-form-item>
      <el-form-item label="模版文件" prop="fileName" class="upload">
        <el-input v-model="parameter.template.fileName" placeholder="请上传模版文件" disabled>
          <template #append>
            <el-upload
              :show-file-list="false"
              :http-request="uploadFile"
              :before-upload="beforeExcelUpload"
              :on-success="excelUploadSuccess"
              :on-error="excelUploadError"
              :accept="parameter.fileType!.join(',')"
            >
              <el-button :icon="UploadFilled" />
            </el-upload>
          </template>
        </el-input>
      </el-form-item>
    </el-form>
    <template #footer>
      <el-button @click="dialogVisible = false">取消</el-button>
      <el-button type="primary" @click="handleSubmit">提交</el-button>
    </template>
  </el-dialog>
</template>

<script setup lang="ts" name="templateEdit">
import type { FormInstance, FormRules, UploadRequestOptions, UploadRawFile } from "element-plus";
import type { SysTemplate, Upload, ResultData } from "@/api/interface";
import { ref, reactive, watch } from "vue";
import { ElMessage, ElNotification } from "element-plus";
import { uploadTemplate } from "@/api/modules/system/upload";
import { UploadFilled } from "@element-plus/icons-vue";

/** 系统模版 */
interface EditProps {
  /** 标题 */
  title: string;
  /** 文件大小 */
  fileSize?: number;
  /** 文件类型 */
  fileType?: File.FileMimeType[];
  /** 待编辑的模版 */
  template: Partial<SysTemplate.Form>;
  /** 获取表格数据的Api */
  getTableList?: () => void;
  /** 提交表单的Api */
  submitApi?: (params: any) => Promise<ResultData<boolean>>;
}

/** 表单实例 */
const formRef = ref<FormInstance>();
/** dialog 状态 */
const dialogVisible = ref(false);
/** 表单验证规则 */
const rules = reactive<FormRules>({
  name: [{ required: true, message: "请输入模版名称", trigger: "blur" }],
  code: [{ required: true, message: "请输入模版编码", trigger: "blur" }],
  fileName: [{ required: true, message: "请上传模版文件", trigger: "blur" }]
});
/** 父组件传过来的参数 */
const parameter = ref<EditProps>({
  title: "",
  fileSize: 2,
  fileType: [
    "application/vnd.ms-excel",
    "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
    "application/msword",
    "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
    "application/pdf",
    "application/zip"
  ],
  template: {}
});

/**
 * 接受父组件传过来的参数
 *
 * @param params 父组件传过来的参数
 * @returns void
 */
const acceptParams = (params: EditProps) => {
  parameter.value = { ...parameter.value, ...params };
  dialogVisible.value = true;
};

/**
 * 初始化表单
 *
 * 1. 重置表单
 *
 * @returns void
 */
const initFormInline = () => {
  formRef.value?.resetFields();
};

/**
 * 文件上传
 *
 * @param param 上传参数
 * @returns 上传接口
 */
const uploadFile = (param: UploadRequestOptions): Promise<ResultData<Upload.Result>> => {
  let excelFormData = new FormData();
  excelFormData.append("file", param.file);
  return uploadTemplate(excelFormData);
};

/**
 * 文件上传之前判断
 *
 * @param file 上传的文件
 * @returns 是否可以上传
 * */
const beforeExcelUpload = (file: UploadRawFile) => {
  const isExcel = parameter.value.fileType!.includes(file.type as File.ExcelMimeType);
  const fileSize = file.size / 1024 / 1024 < parameter.value.fileSize!;
  if (!isExcel)
    ElNotification({
      title: "温馨提示",
      message: "上传文件只能是 xls / xlsx 格式！",
      type: "warning"
    });
  if (!fileSize)
    setTimeout(() => {
      ElNotification({
        title: "温馨提示",
        message: `上传文件大小不能超过 ${parameter.value.fileSize}MB！`,
        type: "warning"
      });
    }, 0);
  return isExcel && fileSize;
};

/**
 * 上传失败提示
 *
 * @returns void
 */
const excelUploadError = () => {
  ElNotification({
    title: "温馨提示",
    message: `上传文件失败，请您重新上传！`,
    type: "error"
  });
};

/**
 * 上传成功提示
 *
 * @param res 上传结果
 * @returns void
 */
const excelUploadSuccess = (res: ResultData<Upload.Result>) => {
  parameter.value.template.fileId = res.data.id;
  parameter.value.template.fileName = res.data.name;
  parameter.value.template.fileSize = res.data.size;

  ElNotification({
    title: "温馨提示",
    message: `文件上传成功！`,
    type: "success"
  });
};

/**
 * 提交表单
 *
 * 1. 校验表单
 * 2. 提交表单
 * 3. 提交结果处理
 * 4. 异常处理
 *
 * @returns void
 */
const handleSubmit = () => {
  formRef.value
    // 1. 校验表单
    ?.validate()
    // 2. 提交表单
    .then(() => {
      return parameter.value.submitApi!(parameter.value.template);
    })
    // 3. 提交结果处理
    .then(({ data }) => {
      if (data) {
        ElMessage.success({ message: `${parameter.value.title}成功！` });
        parameter.value.getTableList!();
        dialogVisible.value = false;
      } else {
        ElMessage.error({ message: `${parameter.value.title}失败！` });
      }
    })
    // 4. 异常处理
    .catch((error: Error) => {
      if (error.message) ElMessage.error({ message: `${parameter.value.title}异常：${error.message}` });
      else ElMessage.error({ message: "请检查表单数据是否填写完整！" });
    });
};

// 监听 dialogVisible 的变化
watch(dialogVisible, val => {
  if (val) {
    initFormInline();
  }
});

// 暴露给父组件的属性和方法
defineExpose({
  acceptParams
});
</script>

<style lang="scss" scoped>
.upload {
  --el-component-size: 30px;
  --el-border: 0;
}
</style>
